package org.thss.petri.gef.commands;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.eclipse.gef.commands.Command;
import org.thss.petri.model.Arc;
import org.thss.petri.model.Place;
import org.thss.petri.model.Token;
import org.thss.petri.model.Transition;

public class FireTransitionCommand extends Command {

	private Transition transition;
	private HashMap<Token, Place> sourceMap;

	public void setTransition(Transition transition) {
		this.transition = transition;
	}

	@Override
	public void execute() {
		this.saveSourceMap(this.transition);
		this.transition.fire();
	}

	@Override
	public boolean canExecute() {
		if (this.transition == null) {
			return false;
		}
		return this.transition.isEnabled();
	}

	@Override
	public void redo() {
		this.execute();
	}

	@Override
	public void undo() {
		this.restoreSourcePlaces(this.transition);
	}

	private void saveSourceMap(Transition transition) {
		sourceMap = new HashMap<Token, Place>();
		for (Arc arc : transition.getIncomings()) {
			Place place = (Place) arc.getSource();
			int count = arc.getWeight();
			for (int i = 0; i < count; i++) {
				Token token = place.getTokens().get(0);
				sourceMap.put(token, place);
			}
		}
	}

	private void restoreSourcePlaces(Transition transition) {
		// remove token from the target place
		// FIXME save newly created tokens
		for (Arc arc : transition.getOutgoings()) {
			Place place = (Place) arc.getTarget();
			int count = arc.getWeight();
			for (int i = 0; i < count; i++) {
				place.getTokens().remove(place.getTokens().size() - 1);
			}
		}
		// restore the token of source place
		Iterator<Entry<Token, Place>> iter = sourceMap.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<Token, Place> entry = iter.next();
			Place src = entry.getValue();
			Token token = entry.getKey();
			token.setPlace(src);
			// FIXME token order may change
			src.getTokens().add(0, token);
		}
		// clear the map
		sourceMap.clear();
	}
}
